import { IonFooter, IonPage, IonSearchbar } from '@ionic/react';
import { useEffect, useState } from 'react';
import * as THREE from 'three';
import { GLTFLoader, MapControls, OrbitControls } from 'three/examples/jsm/Addons.js';

import './Home.css';
import { CapacitorHttp } from '@capacitor/core';

const raycaster = new THREE.Raycaster();

const loader = new GLTFLoader();

interface IRow {
  url: string;
  title: string;
}

export class ModelView {
  renderer: THREE.WebGLRenderer;
  camera: THREE.PerspectiveCamera;
  scene: THREE.Scene;
  controls: OrbitControls;

  rendererBar: THREE.WebGLRenderer;
  cameraBar: THREE.PerspectiveCamera;
  sceneBar: THREE.Scene;

  selected = new THREE.Group();
  objects = new THREE.Group();

  constructor(private canvas: HTMLCanvasElement, private canvasBar: HTMLCanvasElement) {
    const dpr = Math.min(2, window.devicePixelRatio);
    const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
    this.renderer = renderer;
    renderer.setClearColor(0xd3d3d3, 1);
    renderer.setPixelRatio(dpr);

    const camera = new THREE.PerspectiveCamera(75, canvas.width / canvas.height, 0.1, 100);
    camera.position.z = 10;
    camera.position.y = 5;
    this.camera = camera;

    const scene = new THREE.Scene();
    this.scene = scene;
    camera.lookAt(scene.position);
    let controls = new OrbitControls(camera, renderer.domElement);
    this.controls = controls;
    const rendererBar = new THREE.WebGLRenderer({ canvas: canvasBar, antialias: true });
    this.rendererBar = rendererBar;
    rendererBar.setClearColor(0xd3d3d3, 1);
    rendererBar.setPixelRatio(dpr);
    const cameraBar = new THREE.PerspectiveCamera(75, canvasBar.width / canvasBar.height, 0.1, 100);
    cameraBar.position.z = 5;
    cameraBar.position.y = 3;
    this.cameraBar = cameraBar;

    const sceneBar = new THREE.Scene();
    this.sceneBar = sceneBar;
    cameraBar.lookAt(sceneBar.position);
    controls = new MapControls(cameraBar, rendererBar.domElement);
    controls.enableZoom = false;
    controls.enableRotate = false;
    controls.enablePan = true;
    this.onResize();
    this.init();
  }

  init() {
    let scene = this.scene;
    scene.add(new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1));
    const light = new THREE.DirectionalLight(0xffffff, 1.5);
    light.position.set(10, 10, 10);
    scene.add(light);
    this.scene.add(this.selected);
    this.sceneBar.add(new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1));
    this.sceneBar.add(this.objects);

    this.canvasBar.addEventListener('click', (ev) => {
      ev.preventDefault();
      let coords = new THREE.Vector2();
      coords.x = (ev.clientX / this.canvasBar.offsetWidth) * 2 - 1;
      coords.y = -(ev.clientY - this.canvasBar.offsetTop) / this.canvasBar.offsetHeight * 2 + 1;
      raycaster.setFromCamera(coords, this.cameraBar);
      let intersections = raycaster.intersectObjects(this.sceneBar.children);
      if (intersections.length) {
        this.selected.clear();
        let obj = intersections[0].object;
        while(obj.parent && obj.parent != this.objects) obj = obj.parent;
        obj = obj.clone();
        obj.scale.set(4, 4, 4);
        obj.position.set(0, 0, 0);
        this.selected.add(obj);
      }
    });

  }

  randomObjects() {
    const geometries = [
      new THREE.BoxGeometry(1, 1, 1),
      new THREE.SphereGeometry(0.5, 12, 8),
      new THREE.DodecahedronGeometry(0.5),
      new THREE.CylinderGeometry(0.5, 0.5, 1, 12)
    ];
    for (let i = 0; i < 100; i++) {
      const geometry = geometries[geometries.length * Math.random() | 0];
      const material = new THREE.MeshStandardMaterial({
        color: new THREE.Color().setHSL(Math.random(), 1, 0.75, THREE.SRGBColorSpace),
        roughness: 0.5,
        metalness: 0,
        flatShading: true
      });
      let mesh = new THREE.Mesh(geometry, material);
      mesh.position.x = i * 1.5;
      this.objects.add(mesh);
    }
  }

  onResize() {
    let canvas = this.canvas;
    let canvasBar = this.canvasBar;
    const dpr = Math.min(window.devicePixelRatio, 2);
    const h = window.innerHeight / dpr / 4;
    canvas.width = window.innerWidth / dpr;
    canvas.height = window.innerHeight * 0.9 / dpr - h;
    canvasBar.width = window.innerWidth / dpr;
    canvasBar.height = h;

    this.camera.aspect = canvas.width / canvas.height;
    this.camera.updateProjectionMatrix();
    this.renderer.setSize(canvas.width, canvas.height);

    this.cameraBar.aspect = canvasBar.width / canvasBar.height;
    this.cameraBar.updateProjectionMatrix();
    this.rendererBar.setSize(canvasBar.width, canvasBar.height);
  }

  async setRows(rows: Array<IRow>) {
    this.objects.clear();
    //this.randomObjects();
    let x = 0;
    let zero = new THREE.Vector3();
      for (let row of rows) {
      let gltf = await loader.loadAsync(row.url);
      let obj = gltf.scene;
      obj.position.setX(x);
      let scale = new THREE.Vector3();
      obj.getWorldScale(scale);

      console.log(scale.distanceTo(zero));
      x += 1;
      this.objects.add(gltf.scene);
    }
  }

  render(dt: number) {
    let angleY = 1 / 180;
    for (let obj of this.scene.children) {
      obj.rotateY(angleY);
    }
    this.renderer.render(this.scene, this.camera);
    this.rendererBar.render(this.sceneBar, this.cameraBar);
  }
}

const Home: React.FC = () => {

  const [holder, setHolder] = useState<Array<ModelView>>([]);

  const animate = (dt: number) => {
    if (holder.length > 0) {
      holder[0].render(dt);
    }
    requestAnimationFrame(animate);
  }
  useEffect(() => {
    if (holder.length == 0) {
      let canvas = document.getElementById('canvas');
      let canvasBar = document.getElementById('canvas-bar');
      if (canvas instanceof HTMLCanvasElement && canvasBar instanceof HTMLCanvasElement) {
        let app = new ModelView(canvas, canvasBar);
        holder.push(app);
        setHolder(holder);
        window.onresize = () => {
          app?.onResize();
        }
        animate(0);
      }
    } else {
      holder[0].onResize();
    }

  }, holder);


  const search = async (query: string) => {
    const options = {
      url: 'http://www.onceio.top/es/model3d/_search',
      data: {
        "query": {
          "query_string": {
            "query": query
          }
        }
      }
    };
    const response = await CapacitorHttp.post(options);

    console.log('respone', response);

    if (holder.length && response.data.hits) {
      let rows = new Array<IRow>();
      for (let hit of response.data.hits.hits) {
        let item = hit._source;
        let row = { url: `http://www.onceio.top/glb/${item.id}.glb`, title: item.title }
        rows.push(row);
      }
      holder[0].setRows(rows);
    }
  }

  return (
    <IonPage>
      <canvas id="canvas"></canvas>
      <canvas id="canvas-bar"></canvas>
      <IonFooter>
        <IonSearchbar animated={true} placeholder="Keyword" onIonChange={(evt) => {
          evt.preventDefault();
          console.log('--->', evt.target.value);
          if (evt.target.value) {
            search(evt.target.value)
          }
        }}></IonSearchbar>
      </IonFooter>
    </IonPage>
  );
};

export default Home;
